"""
AI简历生成器 - Word文档生成工具
使用python-docx库将AI生成的JSON简历数据转换为专业的Word格式简历
"""

import json
import re
import ast
import os
from datetime import datetime
from docx import Document
from docx.shared import Inches, Pt, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.oxml.shared import OxmlElement, qn
from django.conf import settings


class ResumeDocxGenerator:
    """简历Word文档生成器"""
    
    def __init__(self):
        self.doc = None
        
    def generate_resume_docx(self, resume_json_data, filename=None):
        """
        根据JSON数据生成Word格式简历
        
        Args:
            resume_json_data (dict or str): AI生成的简历JSON数据
            filename (str): 输出文件名，如果不指定则自动生成
            
        Returns:
            str: 生成的文件路径
        """

        print("开始生成简历...")
        print("resume_json_data:",resume_json_data)
        print("resume_json_data的类型:",type(resume_json_data))
        # 解析JSON数据
        if isinstance(resume_json_data, str):
            try:
                # 优先按严格JSON解析
                resume_data = json.loads(resume_json_data)
            except json.JSONDecodeError:
                # 兼容LLM输出为Python风格字典的情况（单引号/None/True/False、包含datetime.date(...)）
                # 1) 先将 'datetime.date(YYYY, M, D)'（带引号）替换为 'YYYY-MM-DD'
                def _replace_datetime_date_quoted(match):
                    year = int(match.group(1))
                    month = int(match.group(2))
                    day = int(match.group(3))
                    return "'" + f"{year:04d}-{month:02d}-{day:02d}" + "'"

                normalized = re.sub(
                    r"'datetime\.date\(\s*(\d{4})\s*,\s*(\d{1,2})\s*,\s*(\d{1,2})\s*\)'",
                    _replace_datetime_date_quoted,
                    resume_json_data,
                )

                # 2) 再将未加引号的 datetime.date(YYYY, M, D) 替换为 'YYYY-MM-DD'
                def _replace_datetime_date_unquoted(match):
                    year = int(match.group(1))
                    month = int(match.group(2))
                    day = int(match.group(3))
                    return "'" + f"{year:04d}-{month:02d}-{day:02d}" + "'"

                normalized = re.sub(
                    r"(?<!')datetime\.date\(\s*(\d{4})\s*,\s*(\d{1,2})\s*,\s*(\d{1,2})\s*\)(?!')",
                    _replace_datetime_date_unquoted,
                    normalized,
                )
                try:
                    # 使用安全的 literal_eval 将 Python 字面量转换为对象
                    resume_data = ast.literal_eval(normalized)
                except Exception as e:
                    raise ValueError(f"JSON解析失败: 无法解析为有效结构 - {e}")
        else:
            resume_data = resume_json_data
            
        # 创建新文档
        self.doc = Document()
        
        # 设置文档页面边距
        self._set_page_margins()
        
        # 生成简历内容
        self._add_header(resume_data.get('基本信息', {}))
        self._add_job_intention(resume_data.get('求职意向', {}))
        self._add_basic_info(resume_data.get('基本信息', {}))
        self._add_work_experience(resume_data.get('工作经历', []))
        self._add_project_experience(resume_data.get('项目经历', []))
        self._add_professional_skills(resume_data.get('专业技能', {}))
        
        # 生成文件名
        if not filename:
            name = resume_data.get('基本信息', {}).get('姓名', 'resume')
            timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
            filename = f"{name}_{timestamp}.docx"
            
        # 确保文件名安全
        filename = self._safe_filename(filename)
        
        # 保存文档
        file_path = self._save_document(filename)
        
        return file_path
    
    def _set_page_margins(self):
        """设置页面边距"""
        sections = self.doc.sections
        for section in sections:
            section.top_margin = Inches(0.5)
            section.bottom_margin = Inches(0.5)
            section.left_margin = Inches(0.75)
            section.right_margin = Inches(0.75)
    
    def _add_header(self, basic_info):
        """添加简历标题和姓名"""
        # 添加标题
        title = self.doc.add_heading('个人简历', level=0)
        title.alignment = WD_ALIGN_PARAGRAPH.CENTER
        
        # 设置标题字体
        title_run = title.runs[0]
        title_run.font.name = '微软雅黑'
        title_run.font.size = Pt(20)
        title_run.font.bold = True
        title_run.font.color.rgb = RGBColor(0x2E, 0x74, 0xB5)
        
        # 添加姓名
        if basic_info.get('姓名'):
            name_para = self.doc.add_paragraph()
            name_para.alignment = WD_ALIGN_PARAGRAPH.CENTER
            name_run = name_para.add_run(basic_info['姓名'])
            name_run.font.name = '微软雅黑'
            name_run.font.size = Pt(16)
            name_run.font.bold = True
            
        # 添加分隔线
        self.doc.add_paragraph('_' * 60).alignment = WD_ALIGN_PARAGRAPH.CENTER
    
    def _add_job_intention(self, job_intention):
        """添加求职意向"""
        if not job_intention:
            return
            
        self._add_section_title('求职意向')
        
        # 创建表格
        table = self.doc.add_table(rows=1, cols=3)
        table.alignment = WD_TABLE_ALIGNMENT.CENTER
        
        # 设置表格样式
        self._set_table_style(table)
        
        # 添加数据
        cells = table.rows[0].cells
        cells[0].text = f"期望职位：{job_intention.get('岗位', '')}"
        cells[1].text = f"期望薪资：{job_intention.get('期望薪资', '')}"
        cells[2].text = f"工作城市：{job_intention.get('城市', '')}"
        
        # 设置单元格字体
        for cell in cells:
            for paragraph in cell.paragraphs:
                for run in paragraph.runs:
                    run.font.name = '微软雅黑'
                    run.font.size = Pt(11)
    
    def _add_basic_info(self, basic_info):
        """添加基本信息"""
        if not basic_info:
            return
            
        self._add_section_title('基本信息')
        
        # 创建基本信息表格
        info_items = [
            ('性别', basic_info.get('性别', '')),
            ('出生日期', basic_info.get('出生日期', '')),
            ('学历', basic_info.get('学历信息', '')),
            ('手机号', basic_info.get('手机号', '')),
            ('邮箱', basic_info.get('邮箱', '')),
            ('当前状态', basic_info.get('当前状态', ''))
        ]
        
        # 过滤空值
        info_items = [(k, v) for k, v in info_items if v]
        
        if info_items:
            # 创建2列表格
            rows = (len(info_items) + 1) // 2
            table = self.doc.add_table(rows=rows, cols=2)
            self._set_table_style(table)
            
            for i, (key, value) in enumerate(info_items):
                row = i // 2
                col = i % 2
                cell = table.cell(row, col)
                cell.text = f"{key}：{value}"
                
                # 设置字体
                for paragraph in cell.paragraphs:
                    for run in paragraph.runs:
                        run.font.name = '微软雅黑'
                        run.font.size = Pt(11)
        
        # 添加个人评价
        if basic_info.get('个人评价'):
            self.doc.add_paragraph()
            eval_para = self.doc.add_paragraph()
            eval_run = eval_para.add_run(f"个人评价：{basic_info['个人评价']}")
            eval_run.font.name = '微软雅黑'
            eval_run.font.size = Pt(11)
    
    def _add_work_experience(self, work_experiences):
        """添加工作经历"""
        if not work_experiences:
            return
            
        self._add_section_title('工作经历')
        
        for i, exp in enumerate(work_experiences):
            # 添加公司和职位信息
            company_para = self.doc.add_paragraph()
            company_run = company_para.add_run(
                f"{exp.get('公司名', '')} | {exp.get('职位', '')}"
            )
            company_run.font.name = '微软雅黑'
            company_run.font.size = Pt(12)
            company_run.font.bold = True
            
            # 添加时间和薪资信息
            time_para = self.doc.add_paragraph()
            time_text = f"{exp.get('开始时间', '')} - {exp.get('结束时间', '')}"
            if exp.get('薪资范围'):
                time_text += f" | 薪资：{exp['薪资范围']}"
            if exp.get('所属行业'):
                time_text += f" | 行业：{exp['所属行业']}"
                
            time_run = time_para.add_run(time_text)
            time_run.font.name = '微软雅黑'
            time_run.font.size = Pt(10)
            time_run.font.color.rgb = RGBColor(0x70, 0x70, 0x70)
            
            # 添加工作描述
            if exp.get('工作描述'):
                desc_para = self.doc.add_paragraph()
                desc_run = desc_para.add_run(f"工作描述：{exp['工作描述']}")
                desc_run.font.name = '微软雅黑'
                desc_run.font.size = Pt(11)
            
            # 如果不是最后一个，添加间距
            if i < len(work_experiences) - 1:
                self.doc.add_paragraph()
    
    def _add_project_experience(self, project_experiences):
        """添加项目经历"""
        if not project_experiences:
            return
            
        self._add_section_title('项目经历')
        
        for i, proj in enumerate(project_experiences):
            # 项目名称
            proj_para = self.doc.add_paragraph()
            proj_run = proj_para.add_run(proj.get('项目名称', ''))
            proj_run.font.name = '微软雅黑'
            proj_run.font.size = Pt(12)
            proj_run.font.bold = True
            
            # 项目时间和角色
            time_role_para = self.doc.add_paragraph()
            time_role_text = f"{proj.get('项目时间', '')} | 角色：{proj.get('项目角色', '')}"
            time_role_run = time_role_para.add_run(time_role_text)
            time_role_run.font.name = '微软雅黑'
            time_role_run.font.size = Pt(10)
            time_role_run.font.color.rgb = RGBColor(0x70, 0x70, 0x70)
            
            # 技术栈
            if proj.get('项目技术栈'):
                tech_para = self.doc.add_paragraph()
                tech_run = tech_para.add_run(f"技术栈：{proj['项目技术栈']}")
                tech_run.font.name = '微软雅黑'
                tech_run.font.size = Pt(10)
                tech_run.font.color.rgb = RGBColor(0x2E, 0x74, 0xB5)
            
            # 项目描述
            if proj.get('项目描述'):
                desc_para = self.doc.add_paragraph()
                desc_run = desc_para.add_run(f"项目描述：{proj['项目描述']}")
                desc_run.font.name = '微软雅黑'
                desc_run.font.size = Pt(11)
            
            # 个人职责
            if proj.get('个人职责'):
                resp_para = self.doc.add_paragraph()
                resp_run = resp_para.add_run(f"个人职责：{proj['个人职责']}")
                resp_run.font.name = '微软雅黑'
                resp_run.font.size = Pt(11)
            
            # 如果不是最后一个，添加间距
            if i < len(project_experiences) - 1:
                self.doc.add_paragraph()
    
    def _add_professional_skills(self, skills):
        """添加专业技能"""
        if not skills:
            return
            
        self._add_section_title('专业技能')
        
        # 按技能等级分组
        skill_levels = {
            '精通': [],
            '熟练': [],
            '了解': [],
            '基础': []
        }
        
        for skill, level in skills.items():
            if level in skill_levels:
                skill_levels[level].append(skill)
        
        # 生成技能列表
        for level, skill_list in skill_levels.items():
            if skill_list:
                skills_para = self.doc.add_paragraph()
                level_run = skills_para.add_run(f"{level}：")
                level_run.font.name = '微软雅黑'
                level_run.font.size = Pt(11)
                level_run.font.bold = True
                
                skills_run = skills_para.add_run(', '.join(skill_list))
                skills_run.font.name = '微软雅黑'
                skills_run.font.size = Pt(11)
    
    def _add_section_title(self, title):
        """添加章节标题"""
        self.doc.add_paragraph()  # 添加空行
        
        section_para = self.doc.add_heading(title, level=1)
        section_run = section_para.runs[0]
        section_run.font.name = '微软雅黑'
        section_run.font.size = Pt(14)
        section_run.font.bold = True
        section_run.font.color.rgb = RGBColor(0x2E, 0x74, 0xB5)
        
        # 添加下划线
        section_para.add_run('_' * 50).font.color.rgb = RGBColor(0xE0, 0xE0, 0xE0)
    
    def _set_table_style(self, table):
        """设置表格样式"""
        # 设置表格边框
        tbl = table._tbl
        tblPr = tbl.tblPr
        
        # 设置表格宽度
        tblW = OxmlElement('w:tblW')
        tblW.set(qn('w:w'), '0')
        tblW.set(qn('w:type'), 'auto')
        tblPr.append(tblW)
        
        # 设置行高
        for row in table.rows:
            tr = row._tr
            trPr = tr.get_or_add_trPr()
            trHeight = OxmlElement('w:trHeight')
            trHeight.set(qn('w:val'), '400')
            trHeight.set(qn('w:hRule'), 'atLeast')
            trPr.append(trHeight)
    
    def _safe_filename(self, filename):
        """确保文件名安全"""
        # 替换不安全字符
        unsafe_chars = ['<', '>', ':', '"', '/', '\\', '|', '?', '*']
        for char in unsafe_chars:
            filename = filename.replace(char, '_')
        return filename
    
    def _save_document(self, filename):
        """保存文档"""
        # 确保uploads目录存在
        upload_dir = os.path.join(settings.MEDIA_ROOT, 'generated_resumes')
        os.makedirs(upload_dir, exist_ok=True)
        
        # 完整文件路径
        file_path = os.path.join(upload_dir, filename)
        
        # 保存文档
        self.doc.save(file_path)
        
        return file_path


def generate_resume_from_ai_response(ai_response, filename=None):
    """
    便捷函数：从AI响应生成简历文档
    
    Args:
        ai_response (str or dict): AI生成的简历JSON数据
        filename (str): 文件名
        
    Returns:
        str: 生成的文件路径
    """
    generator = ResumeDocxGenerator()
    return generator.generate_resume_docx(ai_response, filename)
